﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using DataSimDLL;

namespace BDSim
{
    /// <summary>
    /// 格网序号，在导航服务性能评估中使用
    /// </summary>
    public struct GridIndex
    {
        /// <summary>
        /// 行对应序号
        /// </summary>
        public int RowIndex;

        /// <summary>
        /// 列对应序号
        /// </summary>
        public int ColunmIndex;
    }

    /// <summary>
    /// Dop区域分析评估结果
    /// </summary>
    public class DopAnalysisResult
    {
        public Guid Uid = new Guid();

        public string Name = "";
        /// <summary>
        /// 评估区域所包含格网列表
        /// </summary>
        public List<GridIndex> GridIndexList = new List<GridIndex>();

        /// <summary>
        /// 最小值集合
        /// </summary>
        public List<double> MinValueList = new List<double>();

        /// <summary>
        /// 最大值集合
        /// </summary>
        public List<double> MaxValueList = new List<double>();

        /// <summary>
        /// 平均值集合
        /// </summary>
        public List<double> MeanValueList = new List<double>();

        /// <summary>
        /// 方差集合
        /// </summary>
        public List<double> VarianceList = new List<double>();

        /// <summary>
        /// 时间集合
        /// </summary>
        public List<UTCTime> TimeList = new List<UTCTime>();

        /// <summary>
        /// 往各个集合中添加数据，数据来自评估值列表
        /// </summary>
        /// <param name="EvaluationValueList"></param>
        public void AddData(List<double> EvaluationValueList, UTCTime time)
        {
            if (EvaluationValueList.Count > 0)
            {
                TimeList.Add(time);
                MinValueList.Add(EvaluationValueList.Min());
                MaxValueList.Add(EvaluationValueList.Max());
                double meanValue = EvaluationValueList.Sum() / EvaluationValueList.Count;
                MeanValueList.Add(meanValue);
                double variance = 0;
                for (int i = 0; i < EvaluationValueList.Count; i++)
                {
                    variance += (EvaluationValueList[i] - meanValue) * (EvaluationValueList[i] - meanValue) / EvaluationValueList.Count;
                }
                VarianceList.Add(variance);
            }
        }

        /// <summary>
        /// 清除所有评估数据
        /// </summary>
        public void ClearAllData()
        {
            MinValueList.Clear();
            MaxValueList.Clear();
            MeanValueList.Clear();
            VarianceList.Clear();
        }
    }

    //  [add by [Penghaijun] 2015.1.19
    public enum DopEnum
    {
        /// <summary>
        /// 可见星数目
        /// </summary>
        Coverage = 1,
        /// <summary>
        /// 几何精度因子也是位置精度因子，为纬度、经度和高程等误差平方和的开根号值
        /// </summary>
        GDOP = 2,
        /// <summary>
        /// 三维位置精度因子，为纬度、经度和高程等误差的平方和的开根号值
        /// </summary>
        PDOP = 3,
        /// <summary>
        /// 水平分量精度因子：为纬度和经度等误差平方和的开根号值
        /// </summary>
        HDOP = 4,
        /// <summary>
        /// 垂直分量精度因子
        /// </summary>
        VDOP = 5,
        /// <summary>
        /// 钟差精度因子，为接收仪内时标偏移误差值
        /// </summary>
        TDOP = 6,
        
        HNSP = 7,
        VNSP = 8,
        PNSP = 9,
        TNSP = 10
    }

    public class Dop
    {
        #region 成员定义

        /// <summary>
        /// 覆盖性计算结果
        /// </summary>
        double[,] AccessNum;

        /// <summary>
        /// GDOP计算结果
        /// </summary>
        double[,] GDOP;

        /// <summary>
        /// PDOP计算结果
        /// </summary>
        double[,] PDOP;

        /// <summary>
        /// HDOP计算结果
        /// </summary>
        double[,] HDOP;

        /// <summary>
        /// VDOP计算结果
        /// </summary>
        double[,] VDOP;

        /// <summary>
        /// TDOP计算结果
        /// </summary>
        double[,] TDOP;

        /// <summary>
        /// PNSP计算结果
        /// </summary>
        double[,] PNSP;

        /// <summary>
        /// HNSP计算结果
        /// </summary>
        double[,] HNSP;

        /// <summary>
        /// VNSP计算结果
        /// </summary>
        double[,] VNSP;

        /// <summary>
        /// TNSP计算结果
        /// </summary>
        double[,] TNSP;

        /// <summary>
        /// 颜色种类数量
        /// </summary>
        public int ColorCount { get; set; }

        /// <summary>
        /// 数据行数
        /// </summary>
        public int RowNum { get; set; }

        /// <summary>
        /// 数据列数
        /// </summary>
        public int ColNum { get; set; }


        /// <summary>
        /// 评估值
        /// </summary>
        public double[,] EvaluationValue;
        #endregion

        #region 颜色等级分类
        /// <summary>
        /// 颜色等级分类
        /// </summary>
        /// <param name="colorValue">经纬度处的颜色值集合</param>
        /// <param name="max">最大值</param>
        /// <param name="min">最小值</param>
        /// <returns>颜色字典中的颜色值集合</returns>
        int[,] ColorRank(double[,] colorValue, double maxNum, double minNum)
        {
            int rowNum = colorValue.GetLength(0);//行数
            int colNum = colorValue.GetLength(1);//列数

            int colorType = ColorCount;//颜色字典中，颜色的种类
            double midPart = (maxNum - minNum) / colorType;

            int[,] iColorValue = new int[rowNum, colNum];

            //将颜色值转化成相应的颜色字典中的颜色
            for (int i = 0; i < rowNum; i++)
            {
                for (int j = 0; j < colNum; j++)
                {
                    if (colorValue[i, j] >= maxNum && maxNum == 15)
                    {
                        iColorValue[i, j] = colorType - 1;
                        continue;
                    }
                    else if (colorValue[i, j] >= maxNum && maxNum != 15)
                    {
                        iColorValue[i, j] = -1;
                        continue;
                    }
                    else if (colorValue[i, j] <= minNum)
                    {
                        //此处简化了，意思是当评估的是覆盖性时，可见星小于3的情况不设置颜色
                        if (maxNum == 15)
                        {
                            iColorValue[i, j] = -1;
                        }
                        else
                        {
                            iColorValue[i, j] = 0;
                        }

                        continue;
                    }
                    else if (colorValue[i, j] >= minNum && colorValue[i, j] <= maxNum)
                    {
                        iColorValue[i, j] = (int)((colorValue[i, j] - minNum) / midPart);
                        if (iColorValue[i, j] >= colorType)
                        {
                            iColorValue[i, j] = colorType - 1;
                        }
                        continue;
                    }
                }
            }
            return iColorValue;
        }
        #endregion

        #region 得到颜色数组
        /// <summary>
        /// 得到颜色数组 
        /// </summary>
        /// <param name="satList">卫星位置速度结构体</param>
        /// <returns>颜色数组</returns>
        public int[,] GetColor(ObservableCollection<Satellite> satList, double elelim, DopEnum Type, int satNum, bool IsLinkConsidered, ref double[,] evaluationData)
        {
            List<double> SatXYZList = new List<double>();
            double B, L = 0;
            double EleLim = elelim;  //elelim输入本来就是度

            double H = 100;
            int k = 0;

            foreach (Satellite opv in satList)
            {
                //SatXYZList.Add(opv.satOrbPV.RealTPV.X);
                //SatXYZList.Add(opv.satOrbPV.RealTPV.Y);
                //SatXYZList.Add(opv.satOrbPV.RealTPV.Z);
                SatXYZList.Add(opv.Orbit.RealECFPV.X);
                SatXYZList.Add(opv.Orbit.RealECFPV.Y);
                SatXYZList.Add(opv.Orbit.RealECFPV.Z);
            }

            DopDLL.SetSatsPos(SatXYZList.ToArray(), satNum);

            double deltL = 360.0 / ColNum;
            double deltB = 180.0 / RowNum;

            GDOP = new double[ColNum, RowNum];
            PDOP = new double[ColNum, RowNum];
            HDOP = new double[ColNum, RowNum];
            VDOP = new double[ColNum, RowNum];
            TDOP = new double[ColNum, RowNum];
            PNSP = new double[ColNum, RowNum];
            HNSP = new double[ColNum, RowNum];
            VNSP = new double[ColNum, RowNum];
            TNSP = new double[ColNum, RowNum];
            AccessNum = new double[ColNum, RowNum];

            for (L = -30; L < 330; L = L + deltL, k++)//经度
            {
                double LL = L;
                if (L > 180)
                {
                    LL = L - 360;
                }
                int g = 0;
                for (B = 89; B > -90; B = B - deltB, g++)//纬度
                {
                    DopDLL.DopOutput dopoutput = new DopDLL.DopOutput();

                    DopDLL.CalDop(Type, B, LL, H, EleLim, out dopoutput, IsLinkConsidered);
                    AccessNum[k, g] = dopoutput.AccessNum;
                    GDOP[k, g] = dopoutput.GDOP;
                    PDOP[k, g] = dopoutput.PDOP;
                    HDOP[k, g] = dopoutput.HDOP;
                    VDOP[k, g] = dopoutput.VDOP;
                    TDOP[k, g] = dopoutput.TDOP;
                    HNSP[k, g] = dopoutput.HNSP;
                    VNSP[k, g] = dopoutput.VNSP;
                    PNSP[k, g] = dopoutput.PNSP;
                    TNSP[k, g] = dopoutput.TNSP;
                }
            }

            switch (Type)
            {
                case DopEnum.GDOP:
                    EvaluationValue = GDOP;evaluationData = EvaluationValue;
                    return ColorRank(GDOP, 5, 1); //1-5
                case DopEnum.PDOP:
                    EvaluationValue = PDOP;evaluationData = EvaluationValue;
                    return ColorRank(PDOP, 4, 1.3); //1.3-4
                case DopEnum.HDOP:
                    EvaluationValue = HDOP;evaluationData = EvaluationValue;
                    return ColorRank(HDOP, 3, 0.8);  //0.8-3
                case DopEnum.VDOP:
                    EvaluationValue = VDOP;evaluationData = EvaluationValue;
                    return ColorRank(VDOP, 3, 0.5);//0.5-3
                case DopEnum.TDOP:
                    EvaluationValue = TDOP;evaluationData = EvaluationValue;
                    return ColorRank(TDOP, 2, 0.6);//0.6-2
                case DopEnum.Coverage:
                    EvaluationValue = AccessNum;evaluationData = EvaluationValue;
                    return ColorRank(AccessNum, 15, 3); //3-15
                case DopEnum.HNSP:
                    if (IsLinkConsidered)
                        return ColorRank(HNSP, 2.5, 0.475);//0.475-2.5
                    else
                    {
                        EvaluationValue = HNSP; evaluationData = EvaluationValue;
                        return ColorRank(HNSP, 6, 1.55);//1.55-6
                    }
                case DopEnum.VNSP:
                    if (IsLinkConsidered)
                        return ColorRank(VNSP, 2, 0.3);//0.3-2
                    else
                    {
                        EvaluationValue = VNSP; evaluationData = EvaluationValue;
                        return ColorRank(VNSP, 6, 1);//1-6
                    }
                case DopEnum.PNSP:
                    if (IsLinkConsidered)
                        return ColorRank(PNSP, 2.5, 0.8);//0.8-2.5
                    else
                    {
                        EvaluationValue = PNSP; evaluationData = EvaluationValue;
                        return ColorRank(PNSP, 6.5, 2.5);//2.5-6.5
                    }
                case DopEnum.TNSP:
                    if (IsLinkConsidered)
                        return ColorRank(TNSP, 1.6, 0.4);//0.4-1.6
                    else
                    {
                        EvaluationValue = TNSP; evaluationData = EvaluationValue;
                        return ColorRank(TNSP, 5, 1.2);//1.2-5
                    }
                default:
                    return null;
            }
            
        }
        #endregion

        #region 计算卫星的星下点经纬度
        /// <summary>
        /// 计算卫星的星下点经纬度
        /// </summary>
        /// <param name="satopv"></param>
        /// <returns></returns>
        public double[] GetSatBLH(ObservableCollection<Satellite> satopv)
        {
            int satNum = satopv.Count;
            List<double> SatXYZList = new List<double>();
            DopDLL.BLHData blh = new DopDLL.BLHData();
            //把卫星的ECF坐标同一放到double数组中
            foreach (Satellite opv in satopv)
            {
                SatXYZList.Add(opv.Orbit.RealECFPV.X);
                SatXYZList.Add(opv.Orbit.RealECFPV.Y);
                SatXYZList.Add(opv.Orbit.RealECFPV.Z);
            }
            if (satNum > 0)
            {
                System.Diagnostics.Trace.WriteLine(SatXYZList[0].ToString());
            }
            //定义经纬高
            double[] satBLH = new double[satNum * 3];

            DopDLL.SetSatsPos(SatXYZList.ToArray(), satNum);
            blh.SatsBLH = new double[450];
            DopDLL.GetSatsBLH(ref blh);
            for (int i = 0; i < satNum * 3; i++)
            {
                satBLH[i] = blh.SatsBLH[i];
            }
            return satBLH;
        }
        #endregion
    }

}
